<template>
  <div class="wrap">
    <canvas id="renderCanvas"></canvas>
  </div>
</template>

<script>
import * as BABYLON from "babylonjs"; //全部引入
import * as GEOLIB from "geolib";
export default {
  name: "BabylonMapCom",
  data() {
    return {
      light1: null,
      light2: null,
      sphere: null,
      engine: null,
      canvas: null,
      myMaterial: null,
      myMaterial2: null,
      picMaterial: null,
      center: [117.991394, 36.309121],
    };
  },
  props: {
    msg: String,
  },
  methods: {
    // 创建盒子
    createBox(x, y, z, color) {
      var box = BABYLON.Mesh.CreateBox("box", 10.0, this.scene);
      box.position.x = x;
      box.position.y = y;
      box.position.z = z;
      box.material = new BABYLON.StandardMaterial("texture1", this.scene);
      box.material.diffuseColor = new BABYLON.Color3(
        color[0],
        color[1],
        color[2]
      );
      box.material.specularColor = new BABYLON.Color3(0, 0, 0);
      box.material.emissiveColor = new BABYLON.Color3(0, 0, 0);
      box.material.ambientColor = new BABYLON.Color3(0, 0, 0);
      box.material.backFaceCulling = false;
      box.material.alpha = 0.5;
      // box.material.wireframe = true;
      return box;
    },
    // 获取geo数据
    getGeoJson() {
      fetch("./static/geoJson/shandong.json").then((res) => {
        res.json().then((data) => {
          console.log(data, "data");
          this.loadMap(data);
        });
      });
    },
    loadMap(data) {
      // 有用的数据只有data中的features
      let features = data.features;

      for (let i = 0; i < features.length; i++) {
        let fel = features[i];

        if (!fel["properties"]) return;

        let info = fel.properties;
        let height = 6;
        this.addBuilding(fel.geometry.coordinates, info, height);
      }
    },

    addBuilding(data, info, height) {
      for (let i = 0; i < data.length; i++) {
        let el = data[i];
        let shapeAll = this.getShape(el[0], this.center, height);
        // 获取到形状
        let shape = shapeAll.shape;
        let linesShape = shapeAll.linesShape;
        const building = BABYLON.MeshBuilder.ExtrudePolygon("building", {
          shape: shape,
          depth: height,
          sideOrientation: BABYLON.Mesh.DOUBLESIDE,
        });
        const lines = BABYLON.MeshBuilder.CreateLines("lines", {
          points: linesShape,
        });
        lines.rotation.z = Math.PI;
        lines.color = new BABYLON.Color3(1, 1, 1);
        building.rotation.z = Math.PI;
        building.material = this.myMaterial2;
        building.name = info["name"] ? info["name"] : "map";
        building.info = info;
        // building.rotation.x = Math.PI;
        // console.log(shape, height, "1");
        // const name =
      }
    },
    getShape(points, center, height) {
      let shape = [];
      let linesShape = [];
      for (let i = 0; i < points.length; i++) {
        let elp = points[i];

        elp = this.gpsRelativePosition(elp, center);

        shape.push(new BABYLON.Vector3(elp[0], 0, elp[1]));
        linesShape.push(new BABYLON.Vector3(elp[0], -height, elp[1]));
      }
      console.log(shape, "什么形状的");
      return { shape, linesShape };
    },
    gpsRelativePosition(objPos, centerPos) {
      // 获取 gps 距离
      let dis = GEOLIB.getDistance(objPos, centerPos);

      // 获取夹角
      let bearing = GEOLIB.getRhumbLineBearing(objPos, centerPos);

      // 计算x
      let x = centerPos[0] + dis * Math.cos((bearing * Math.PI) / 180);

      // 计算y
      let y = centerPos[1] + dis * Math.sin((bearing * Math.PI) / 180);

      return [x / 7000, y / 7000];
    },
    // 按原始坐标绘制的话，两点之间经纬度差别小，并且坐标点很大数值很大，远离3d引擎的坐标原点（0, 0, 0），需要进行坐标转换，设定中心点，算出各个经纬度点相对中心点的相对坐标
    // 因为地球是球面，小范围内用经纬度点减去原点坐标，不会有相对距离偏差，如果范围大就要将球面坐标，做平面投影，常用的是墨卡托投影

    // babylon创建场景
    /******* Add the create scene function ******/
    createScene() {
      // 创建一个场景scene
      var scene = new BABYLON.Scene(this.engine);

      // 添加一个相机，并绑定鼠标事件
      var camera = new BABYLON.ArcRotateCamera(
        "Camera",
        3.3,
        0.7,
        100,
        new BABYLON.Vector3(0, 0, 0),
        scene
      );
      camera.attachControl(this.canvas, true);
      camera.upperBetaLimit = Math.PI / 2.2;

      // 添加一组灯光到场景
      this.light1 = new BABYLON.HemisphericLight(
        "light1",
        new BABYLON.Vector3(1, 1, 0.3),
        scene
      );
      this.light1.intensity = 0.5;

      // 点光源
      // this.light2 = new BABYLON.PointLight(
      //   "light2",
      //   new BABYLON.Vector3(0, 10, -1),
      //   scene
      // );
      // this.light2.intensity = 0.5;

      // 颜色纹理 -- 绿
      this.myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
      this.myMaterial.emissiveColor = new BABYLON.Color3(
        17 / 256,
        239 / 256,
        239 / 256
      );

      // 颜色纹理 -- 蓝
      this.myMaterial2 = new BABYLON.StandardMaterial("myMaterial2", scene);
      this.myMaterial2.diffuseColor = new BABYLON.Color3(0.1, 0.5, 0.9);

      // 图片纹理
      this.picMaterial = new BABYLON.StandardMaterial("boxMaterial2", scene);
      this.picMaterial.diffuseTexture = new BABYLON.Texture(
        "https://ts1.cn.mm.bing.net/th/id/R-C.a902a2666359a8cdfdb4a5073d402423?rik=%2fOAi8FFhylA5IQ&riu=http%3a%2f%2fimg.ewebweb.com%2fuploads%2f20191203%2f19%2f1575371671-fMmhxsnHNX.jpg&ehk=R7dew66vN%2bgvvyJL3I8BL00tsQwYL%2bv8PIqeUSKgzk4%3d&risl=&pid=ImgRaw&r=0",
        scene
      );

      let oldPickMesh = null;

      scene.onPointerDown = (evt, pickResult) => {
        // if the click hits the ground object, we change the impact position
        if (pickResult.hit) {
          // impact.position.x = pickResult.pickedPoint.x;
          // impact.position.y = pickResult.pickedPoint.y;
          if (oldPickMesh) {
            oldPickMesh.material = this.myMaterial2;
            oldPickMesh.position.y = 0;
          }
          console.log(pickResult.hit, "点击", pickResult);
          pickResult.pickedMesh.material = this.myMaterial;
          pickResult.pickedMesh.position.y += 1;
          oldPickMesh = pickResult.pickedMesh;
        }
      };

      return scene;
    },
  },
  mounted() {
    this.canvas = document.getElementById("renderCanvas"); // 得到canvas对象的引用
    this.engine = new BABYLON.Engine(this.canvas, true); // 初始化 BABYLON 3D engine

    /******* End of the create scene function ******/

    this.scene = this.createScene(); //Call the createScene function

    // 创建盒子
    // let box = this.createBox(0, 0, 0, [1, 0, 1]);

    // 最后一步调用engine的runRenderLoop方案，执行scene.render()，让我们的3d场景渲染起来
    this.engine.runRenderLoop(() => {
      this.scene.render();
    });

    // 监听浏览器改变大小的事件，通过调用engine.resize()来自适应窗口大小
    window.addEventListener("resize", () => {
      this.engine.resize();
    });
    this.getGeoJson();
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.wrap {
  height: 100vh;
  width: 100vw;

  #renderCanvas {
    height: 100%;
    width: 100%;
  }
}
</style>
